﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Data.SqlTypes;
using System.Web.Security;
using System.Web.UI;

namespace Team4
{
    // Business Logic Layer - all code/classes that does not "fit" in the code behind goes in here.
    // - this code is accessed by the aspx page codebehind and can access the DAL for database data.
    public class BLL
    {
        // This class is used by the touchscreen and the web ui to view, add and edit room reservations.
        // Rename or make changes to this class as needed
        [Serializable]
        public class CalendarEvent
        {
            public int Id { get; set; }
            public string Title { get; set; }
            public bool AllDay { get; set; }
            public DateTime Start { get; set; }
            public DateTime End { get; set; }
            public string Url { get; set; }
            public string ClassName { get; set; }
            public bool Editable { get; set; }
            public int RoomCode { get; set; }
            public string UserName { get; set; }

            public CalendarEvent()
            {
                Id = -1;
                Title = string.Empty;
                Url = string.Empty;
                ClassName = string.Empty;
                AllDay = false;
                Start = DateTime.MinValue;
                End = DateTime.MinValue;
                Editable = false;
                RoomCode = -1;
                UserName = string.Empty;
            }

            public CalendarEvent(string id, string title, string allDay, string start, string end,
                                string url, string className, string editable, string roomCode, string userName)
            {
                Title = (title.Equals("NULL")) ? string.Empty : title;
                Url = (url.Equals("NULL")) ? string.Empty : url;
                ClassName = (className.Equals("NULL")) ? string.Empty : className;

                try
                {
                    Id = int.Parse(id);
                    AllDay = bool.Parse(allDay);
                    Start = ConvertFromString(start);
                    End = ConvertFromString(end);
                    Editable = bool.Parse(editable);
                    RoomCode = int.Parse(roomCode);
                    UserName = userName;
                }
                catch(Exception ex)
                {
                    Id = -1;
                    AllDay = false;
                    Start = DateTime.MinValue;
                    End = DateTime.MinValue;
                    Editable = false;
                    RoomCode = -1;
                    UserName = string.Empty;
                }
            }

            public void Save()
            {
                try
                {
                    if (Id > 0)
                    {
                        if (string.IsNullOrWhiteSpace(Title))
                        {
                            DAL.CalendarEvent_Data.Delete(ConvertToSQL(new CalendarEvent[] { this })[0]);
                        }
                        else
                        {
                            DAL.CalendarEvent_Data.Update(ConvertToSQL(new CalendarEvent[] { this })[0]);
                        }
                    }
                    else
                    {
                        DAL.CalendarEvent_Data.Create(ConvertToSQL(new CalendarEvent[] { this })[0]);
                    }
                }
                catch (Exception ex)
                {
                    
                }
                
            }

            public static CalendarEvent[] GetEventsForRoomInRange(string startDateRange, string endDateRange, string roomCode)
            {
                DAL.CalendarEvent_Data[] sqlEvents = DAL.CalendarEvent_Data.GetEventsForRoomInRange(new SqlDateTime(ConvertFromString(startDateRange)),
                                                                                                    new SqlDateTime(ConvertFromString(endDateRange)),
                                                                                                    new SqlInt32(Convert.ToInt32(roomCode)));

                // Only editable for current user.
                foreach (var calendarEventData in sqlEvents)
                {
                    calendarEventData.Editable =
                        HttpContext.Current.User.Identity.Name.Equals(calendarEventData.UserName.Value);
                }

                return CalendarEvent.ConvertFromSQL(sqlEvents);
            }

            private static DateTime ConvertFromString(string dt)
            {
                DateTime convertedDate = DateTime.SpecifyKind(
                    DateTime.Parse(dt),
                    DateTimeKind.Local);

                return convertedDate;
            }

            private static CalendarEvent[] ConvertFromSQL(DAL.CalendarEvent_Data[] objArray)
            {
                CalendarEvent[] ea = new CalendarEvent[objArray.Length];

                for (int i = 0; i < objArray.Length; i++ )
                {
                    ea[i] = new CalendarEvent()
                    {
                        Id = objArray[i].Id.Value,
                        Title = (objArray[i].Title.IsNull) ? string.Empty : objArray[i].Title.Value,
                        AllDay = (objArray[i].AllDay.IsNull) ? false : objArray[i].AllDay.Value,
                        Start = (objArray[i].Start.IsNull) ? SqlDateTime.MinValue.Value : objArray[i].Start.Value,
                        End = (objArray[i].End.IsNull) ? SqlDateTime.MinValue.Value : objArray[i].End.Value,
                        Url = (objArray[i].Url.IsNull) ? string.Empty : objArray[i].Url.Value,
                        ClassName = (objArray[i].ClassName.IsNull) ? string.Empty : objArray[i].ClassName.Value,
                        Editable = (objArray[i].Editable.IsNull) ? false : objArray[i].Editable.Value,
                        RoomCode = (objArray[i].RoomCode.IsNull) ? -1 : objArray[i].RoomCode.Value,
                        UserName = (objArray[i].UserName.IsNull) ? string.Empty : objArray[i].UserName.Value
                    };
                }

                return ea;
            }

            private static DAL.CalendarEvent_Data[] ConvertToSQL(CalendarEvent[] objArray)
            {
                DAL.CalendarEvent_Data[] ea = new DAL.CalendarEvent_Data[objArray.Length];
                
                for (int i = 0; i < objArray.Length; i++)
                {
                    ea[i] = new DAL.CalendarEvent_Data()
                    {
                        Id = objArray[i].Id,
                        Title = (string.IsNullOrWhiteSpace(objArray[i].Title)) ? SqlString.Null : objArray[i].Title,
                        AllDay = objArray[i].AllDay,
                        Start = (objArray[i].Start.Equals(SqlDateTime.MinValue)) ? SqlDateTime.Null : objArray[i].Start,
                        End = (objArray[i].End.Equals(SqlDateTime.MinValue)) ? SqlDateTime.Null : objArray[i].End,
                        Url = (string.IsNullOrWhiteSpace(objArray[i].Url)) ? SqlString.Null : objArray[i].Url,
                        ClassName = (string.IsNullOrWhiteSpace(objArray[i].ClassName)) ? SqlString.Null : objArray[i].ClassName,
                        Editable = objArray[i].Editable,
                        RoomCode = objArray[i].RoomCode,
                        UserName = (string.IsNullOrWhiteSpace(objArray[i].UserName)) ? SqlString.Null : objArray[i].UserName
                    };
                }

                return ea;
            }
        }

        // Rename or make changes to this class as needed
        public class Room
        {
            public string TextField { get { return Number + " - " + Name; } }
            public int Id { get; set; }
            public string Name { get; set; }
            public string Number { get; set; }

            public static List<Room> Rooms { get { return DAL.Room_Data.GetListofRooms(); } }

            public static List<Room> GetAllRooms()
            {
                return DAL.Room_Data.GetListofRooms();
            }

            public static Room GetRoom(Room rm)
            {
                return ConvertFromRoomData(DAL.Room_Data.Read(rm.Id));
            }

            public static Room CreateRoom(Room rm)
            {
                return ConvertFromRoomData(DAL.Room_Data.Create(ConvertToRoomData(rm)));
            }

            public static Room UpdateRoom(Room rm)
            {
                return ConvertFromRoomData(DAL.Room_Data.Update(ConvertToRoomData(rm)));
            }

            public static Room DeleteRoom(Room rm)
            {
                return ConvertFromRoomData(DAL.Room_Data.Delete(ConvertToRoomData(rm)));
            }

            private static Room ConvertFromRoomData(DAL.Room_Data rd)
            {
                Room rm = new Room()
                              {
                                  Id = -1,
                                  Name = string.Empty,
                                  Number = string.Empty
                              };

                if (rd != null)
                {
                    rm.Id = rd.Id.Value;
                    rm.Name = rd.Name.Value;
                    rm.Number = rd.Number.Value;
                }

                return rm;
            }
            private static DAL.Room_Data ConvertToRoomData(Room rm)
            {
                DAL.Room_Data rd = new DAL.Room_Data()
                {
                    Id = -1,
                    Name = string.Empty,
                    Number = string.Empty
                };

                if (rm != null)
                {
                    rd.Id = rm.Id;
                    rd.Name = rm.Name;
                    rd.Number = rm.Number;
                }

                return rd;
            }
        }

        public class User
        {
            public static bool IsAdmin(string userName)
            {
                return Roles.IsUserInRole(userName, AdminRoleName);
            }
   
            private const string AdminRoleName = "Admin";

            public static List<User> GetAllUsers()
            {
                List<User> uList = new List<User>();

                foreach (MembershipUser user in Membership.GetAllUsers())
                {
                    uList.Add(User.GetUser(user.UserName));
                }

                return uList;
            }
                
            public string UserName { get; set; }
            public string EmailAddress { get; set; }
            public bool Admin { get; set; }

            public static User GetUser(string userName)
            {
                User u = new User()
                                {
                                    UserName = string.Empty,
                                    EmailAddress = string.Empty,
                                    Admin = false
                                };
                MembershipUser mu = Membership.GetUser(userName);

                if (mu != null)
                {
                    u.UserName = mu.UserName;
                    u.EmailAddress = mu.Email;
                    u.Admin = Roles.IsUserInRole(userName, AdminRoleName);
                }

                return u;
            }

            public static User UpdateUser(User user)
            {
                MembershipUser u = Membership.GetUser(user.UserName);
                u.Email = user.EmailAddress;
                    
                Membership.UpdateUser(u);

                // Cannot change username, so make sure we set it back.
                user.UserName = u.UserName;

                SetAdmin(user.UserName, user.Admin);

                return user;
            }

            public static User DeletUser(User user)
            {
                Membership.DeleteUser(user.UserName);
                return user;
            }

            // $Password1 is the default password used to create a user if the user does not provide one.
            public static User CreateUser(string userName, string email, bool admin, string password = "$Password1")
            {
                if (Membership.GetUser(userName) == null)
                {
                    if (string.IsNullOrWhiteSpace(password))
                    {
                        Membership.CreateUser(userName, "$Password1", email);
                    }
                    else
                    {
                        Membership.CreateUser(userName, password, email);   
                    }
                }

                SetAdmin(userName, admin);

                return GetUser(userName);
            }

            private static void SetAdmin(string userName, bool admin)
            {
                if (admin)
                {
                    // Put user in role
                    if (!Roles.IsUserInRole(userName, AdminRoleName))
                    {
                        Roles.AddUserToRole(userName, AdminRoleName);
                    }
                }
                else
                {
                    // Remove user from role
                    if (Roles.IsUserInRole(userName, AdminRoleName))
                    {
                        Roles.RemoveUserFromRole(userName, AdminRoleName);
                    }
                }
            }
        }

        public class Security
        {
            private const String NotAuthenticatedUrl = "~/Account/Login.aspx";
            private const String NoPermissionsUrl = "~/Default.aspx";
            
            public static void PageSecurity(Page page)
            {
                // Is users session authenticated?
                if (!(page.User.Identity.IsAuthenticated))
                    page.Response.Redirect(NotAuthenticatedUrl);
            }

            public static void PageSecurityAdminOnly(Page page)
            {
                // Is users session authenticated?
                if (!(page.User.Identity.IsAuthenticated))
                    page.Response.Redirect(NotAuthenticatedUrl);

                // Does user have permission to view page?
                if (!User.IsAdmin(page.User.Identity.Name))
                    page.Response.Redirect(NoPermissionsUrl);
            }
        }
    }
}